﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;
using HSDc.DefinitionTransformer.DTO;

namespace HSDc.DefinitionTransformer.Entity
{
    internal class Transform
    {
        private RequiredIntf.IDiagramSupport digSupport = null;
        private int _diagramId;
        private string _resourceId;

        public Process Excute(int diagramId, string resourceId) 
        {
            _diagramId = diagramId;
            _resourceId = resourceId;
            digSupport = GetDiagramSupport("transformer/DiagramSupport");

            //todo Arthur Fork and Join
            Process proc = CreateProcess();

            return proc;
        }

        public void Commit(Entity.Process proc) 
        {
      
            DBBoundary.ProcessRepository _pRepo = new DBBoundary.ProcessRepository();
            _pRepo.Add(proc);
        
        }

        private Process CreateProcess() 
        {

            Process proc = new Process();
            ProcessElement startpoint = CreateProcessElement(digSupport.GetStartPointElement(_diagramId, _resourceId));
            proc = CreateBlock(proc, startpoint);

            return proc;
        
        }

        private Process CreateBlock(Process proc, ProcessElement procElement)
        {
           
           List<DiagramElement> digElements =digSupport.GetConnector(_diagramId,_resourceId,procElement.Id );

           if (digElements != null)
            {
              
                foreach (DiagramElement item in digElements)
                {
                    Connector conn = (Connector)item;
                    Transition transition = (Transition)CreateProcessElement(item);

                    if (!IsTransitionCreated(proc, transition.Id))
                    {
                        proc.Transitions.Add(transition);

                        ProcessElement source = CreateProcessElement(digSupport.GetElement(_diagramId, _resourceId, conn.SourceElementId));
                        ProcessElement target = CreateProcessElement(digSupport.GetElement(_diagramId, _resourceId, conn.TargetElementId));

                        AddSwimlaneToProc(proc, CreateSwimlane(proc, source));
                        AddSwimlaneToProc(proc, CreateSwimlane(proc, target));

                        if (!IsElementCreated(proc, source.Id)) proc.ConnectedElements.Add(source);
                        if (!IsElementCreated(proc, target.Id)) proc.ConnectedElements.Add(target);

                        proc = CreateBlock(proc, target);
                    }
         
                }
            }

            return proc;

        }

        private ProcessElement CreateProcessElement(DiagramElement element)
        {
            ProcessElement procElement = null;
            if (element.Type == ElementType.StartPoint) procElement = new StartPoint();
            if (element.Type == ElementType.Activity)  procElement = new Activity();
            if (element.Type == ElementType.Decision)   procElement = new Decision();
            if (element.Type == ElementType.Action) procElement = new  Activity();
            if (element.Type == ElementType.EndPoint) procElement = new  EndPoint();
            if (element.Type == ElementType.Partition) procElement = new Swimlane();
            if (element.Type == ElementType.Fork) procElement = new  Fork();
            if (element.Type == ElementType.Join) procElement = new Join();

            if (element.Type == ElementType.Transition)
            {
                procElement  = new  Transition();
                ((Transition)procElement).TargetId = ((Connector)element).TargetElementId;
                ((Transition)procElement).SourceId = ((Connector)element).SourceElementId;
                ((Transition)procElement).Constraint = ((Connector)element).Constraint;
            }


            procElement.Id = element.Id;
            procElement.Name = element.Name;
            procElement.ParentId = element.ParentId;

            return procElement;
        }

        private Entity.Swimlane CreateSwimlane(Process proc , ProcessElement procElement  ) 
        {
            Entity.Swimlane swimlane = null;
            if (procElement.ParentId != 0)
            {
                if (!IsSwimlaneCreated(proc, procElement.ParentId)) {
                    ProcessElement newElement = CreateProcessElement(digSupport.GetElement(_diagramId, _resourceId, procElement.ParentId));
                    if (newElement.GetType() == typeof(Entity.Swimlane)) {
                        swimlane = (Entity.Swimlane)newElement;
                        swimlane.SeqNo = proc.FindMaxSwimlaneSeqNo() + 1;

                    }

                }

            }

            return swimlane;
        }

        private bool IsTransitionCreated(Process proc, int transitionId) 
        {

            var result = from s in proc.Transitions where s.Id == transitionId select s;
            if (result.Count() > 0)
                return true;
            else
                return false;

        }

        private bool IsSwimlaneCreated(Process proc, int swimlaneId)
        {

            var result = from s in proc.Swimlanes where s.Id == swimlaneId select s;
            if (result.Count() > 0)
                return true;
            else
                return false;

        }

        private bool IsElementCreated(Process proc, int elementId)
        {

            var result = from s in proc.ConnectedElements where s.Id == elementId select s;
            if (result.Count() > 0)
                return true;
            else
                return false;

        }

        private void AddSwimlaneToProc(Process proc, Swimlane swimlane) 
        {
            if (swimlane != null)
                proc.Swimlanes.Add(swimlane);

        }

        private  RequiredIntf.IDiagramSupport GetDiagramSupport(string configName)
        {
            Util.ConfigurationSectionHelper configSection = new Util.ConfigurationSectionHelper();
            string configPath = configSection.GetType().Assembly.CodeBase.Substring(8).Replace("/", "\\");
            Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(configPath);
            //string className = (string)config.GetSection(configName).ElementInformation.Properties["className"].Value;
            //temp
            string className = "HSDc.EABoundary.DiagramSupport";
            AssemblyName myAssemblyName = new AssemblyName();
            //myAssemblyName.Name = config.GetSection(configName).ElementInformation.Properties["dllName"].Value.ToString();
            myAssemblyName.Name = "EABoundary";
            myAssemblyName.CodeBase = configSection.GetType().Assembly.CodeBase;
            //myAssemblyName.CodeBase = myAssemblyName.CodeBase.Substring(0, myAssemblyName.CodeBase.LastIndexOf("/")) +"/"+ myAssemblyName.Name + ".DLL";
            Assembly instance = Assembly.Load(myAssemblyName);
           //temp Arhtur
            Type classType = instance.GetType(className);
            return (RequiredIntf.IDiagramSupport)System.Activator.CreateInstance(classType);
        }


    }
}
